package org.fas.air.base
{
	import flash.desktop.NativeApplication;
	import flash.desktop.Updater;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLStream;
	import flash.utils.ByteArray;
	import flash.utils.clearTimeout;
	import flash.utils.setTimeout;
	
	import mx.controls.TextArea;
	
	public class FAutoUpdateOfficial extends EventDispatcher
	{
		public var needRestart:Boolean = false;
		static public const TOO_LOWEST:String = "TOO_LOWEST";
		static public const NET_ERROR:String = "NET_ERROR";
		static public const INSTALL_ERROR:String = "INSTALL_ERROR";
		static public const DOWNLOAD_IO_ERROR:String = "DOWNLOAD_IO_ERROR";
		static public const DOWNLOAD_SECURITY_ERROR:String = "DOWNLOAD_SECURITY_ERROR";
		static public const DONE:String = "DONE";
		static public const DOWNLOADING:String = "DOWNLOADING";
		static public const PROGRESSING:String = "PROGRESSING";
		static public const INSTALLING:String = "INSTALLING";
		public var serverVersion:String = '';
		public var localVersion:String = '';
		public var nowDownIndex:int = 0;
		private var downFiles:Array = new Array();
		public var url_update:String;
		public var url_update_folder:String;
		private var urlStream:URLStream;
		private var callback:Function;
		private var urlLoader:URLLoader;
		public var shower:TextArea;
		public function FAutoUpdateOfficial()
		{
		}
		public function get fileSum():int{
			return this.downFiles.length;
		}
		private var timerId:int = -1;
		public function check(_callback:Function):void{
			this.callback = _callback;
			this.getLocalVersionFromApp();
			this.getServerVersion();
		}
		private function getLocalVersionFromApp():void{
			var _appdate:String = (NativeApplication.nativeApplication.applicationDescriptor);
			_appdate  = _appdate.split('<version>')[1];
			_appdate  = _appdate.split('</version>')[0];
			 this.localVersion = _appdate;
		}
		private function evtNetTimeOut():void{
			this.evtNetError();
		}
		private function evtNetError(_e:IOErrorEvent=null):void{
			this.clearTimer();
			this.removeNetEvent();
			this.callback(NET_ERROR);
		}
		private function addNetEvent():void{
			urlLoader.addEventListener(IOErrorEvent.IO_ERROR,this.evtNetError);
		}
		private function removeNetEvent():void{
			urlLoader.removeEventListener(IOErrorEvent.IO_ERROR,evtNetError);
		}
		private function setTimer():void{
			if(this.timerId!=-1){
				this.clearTimer();
			}
//			timerId = flash.utils.setTimeout(evtNetTimeOut,16000);
		}
		private function clearTimer():void{
			flash.utils.clearTimeout(this.timerId);
			this.timerId = -1;
		}
		private function getServerVersion():void{
			//check service version
			setTimer();
			this.urlLoader = new URLLoader();
			this.addNetEvent();
			urlLoader.addEventListener(Event.COMPLETE,this.getServerVersionCb);
			urlLoader.load(new URLRequest(this.url_update));
		}
		private function getServerVersionCb(_e:Event):void{
			this.clearTimer();
			this.removeNetEvent();
			urlLoader.removeEventListener(Event.COMPLETE,this.getServerVersionCb);
			checkServerVersion(_e.target.data);
		}
		private function checkServerVersion(_result:Object):void{
			var _server:XML = XML(_result);
			this.serverVersion = _server.item[0].version;
			//
			var _lowest_ver:String = _server.item[0].lowest_version;
			//
			var files:XMLList = _server.item[0].file;
			for(var i:int = 0;i<files.length();i++){
				this.downFiles.push(files[i]);
			}
			//
			if(Number(localVersion)<Number(_lowest_ver)){
				this.callback(TOO_LOWEST);
				return;
			}
			//
			if(Number(serverVersion)>Number(localVersion)){
				this.download();
			}else{
				this.sayComplete();
			}
		}
		private var tempDirectory:File;
		public function download():void{
			this.log('Begin download');
			try{
			//create temp directory
//			var _directory:File = new File(File.applicationDirectory.resolvePath('temp').nativePath);
			this.tempDirectory = File.createTempDirectory();
			this.log('temp directory',this.tempDirectory);
			this.nowDownIndex = 0;
			downFileSimple();
			}catch(_e:Error){
				this.log('down error ',_e.errorID,_e.message,_e.name);
			}
		}
		private function downFileSimple():void{
			this.log('Begin download simple file');
			try{
				this.callback(DOWNLOADING);
				var _reg:URLRequest = new URLRequest(this.url_update_folder+this.downFiles[nowDownIndex]);
				this.urlStream = new URLStream();
				this.newFile = new File(this.tempDirectory.nativePath +'/'+ this.downFiles[nowDownIndex].toString());
				this.newFileStream = new FileStream();
				newFileStream.open(newFile,FileMode.WRITE);
				urlStream.removeEventListener(Event.COMPLETE,downloadFileComplete);
				urlStream.removeEventListener(ProgressEvent.PROGRESS,downloadProgress);
				urlStream.removeEventListener(IOErrorEvent.IO_ERROR,downloadIoError);
				urlStream.removeEventListener(SecurityErrorEvent.SECURITY_ERROR,downloadSecurityError);
				urlStream.addEventListener(Event.COMPLETE,downloadFileComplete);
				urlStream.addEventListener(ProgressEvent.PROGRESS,downloadProgress);
				urlStream.addEventListener(IOErrorEvent.IO_ERROR,downloadIoError);
				urlStream.addEventListener(HTTPStatusEvent.HTTP_STATUS,downloadHttpStatusHandler);
				urlStream.addEventListener(HTTPStatusEvent.HTTP_RESPONSE_STATUS,downloadHttpResponseStatusHandler);
				urlStream.addEventListener(SecurityErrorEvent.SECURITY_ERROR,downloadSecurityError);
				urlStream.load(_reg);
			}catch(_e:Error){
				this.log('down simple error ',_e.errorID,_e.message,_e.name,_e.getStackTrace());
			}
		}
		private function downloadIoError(_e:IOErrorEvent):void{
			this.callback(FAutoUpdate.DOWNLOAD_IO_ERROR);
		}
		private function downloadSecurityError(_e:SecurityErrorEvent):void{
			this.callback(FAutoUpdate.DOWNLOAD_SECURITY_ERROR);
		}
		private function downloadHttpResponseStatusHandler(event:HTTPStatusEvent):void{
		}
		private function downloadHttpStatusHandler(event:HTTPStatusEvent):void{
		}
		public var downTotal:Number = 1;
		public var downLoaded:Number = 0;
		private function downloadProgress(_e:ProgressEvent):void{
			try{
				downLoaded = _e.bytesLoaded;
				downTotal = _e.bytesTotal;
//				this.log('Down progress',_e.bytesLoaded,_e.bytesTotal);
				this.callback(PROGRESSING);
				if(this.urlStream.bytesAvailable>51200){
					var data:ByteArray = new ByteArray();
					this.urlStream.readBytes(data,0,this.urlStream.bytesAvailable);
					this.newFileStream.writeBytes(data,0,data.length);
				}
			}catch(_e:Error){
				this.log('down simple progress error ',_e.errorID,_e.message,_e.name,_e.getStackTrace());
			}
		}
		private var newFile:File;
		private var newFileStream:FileStream;
		private function downloadFileComplete(_e:Event):void{
			var data:ByteArray=new ByteArray();
			urlStream.readBytes(data,0,this.urlStream.bytesAvailable);
			newFileStream.writeBytes(data,0,data.length);
			newFileStream.close();
			if(this.nowDownIndex<this.downFiles.length-1){
				this.nowDownIndex++;
				this.downFileSimple();
			}else{
				install();
			}
		}
		private function install():void{
			this.callback(INSTALLING);
			var _fileName:String;
			for(var i:int = 0;i<this.downFiles.length;i++){
				_fileName = this.downFiles[i].toString();
				var oldFile:File = new File(this.tempDirectory.nativePath +'/'+ _fileName);
				if(_fileName.indexOf('.air')!=-1){//ffp.air file don't need copy to app folder  but need update
					this.airFileName = _fileName;
				}else{
					var newFile:File = new File(File.applicationDirectory.resolvePath(_fileName).nativePath);
					oldFile.copyTo(newFile,true);
				}
			}
			this.updateLocalVersion();
		}
		/**
		 * modify config.xml
		 * 
		 */		
		private var airFileName:String = '';
		private function updateLocalVersion():void{
//			this.saveUpdateConfig();
//			trace(this.airFileName);
			if(this.airFileName){
				var _updater:Updater = new Updater();
				_updater.update(new File(this.tempDirectory.nativePath +'/'+ this.airFileName),this.serverVersion);
			}else{
//				trace('done');
				this.sayComplete();
			}
		}
		private function sayComplete():void{
			//delete directory:temp
			if(this.tempDirectory && this.tempDirectory.exists){
				this.tempDirectory.	deleteDirectory(true);
			}
			this.callback(DONE);
		}
		//
		private function log(...args):void{
			var _arr:Array = args as Array;
			var _str:String = '\n';
			for(var i:int=0;i<_arr.length;i++){
				if(_arr[i]){
					_str += (_arr[i].toString()+' ');
				}
			}
			if(this.shower){
				this.shower.text += _str;
			}
			
		}
		/*private function saveUpdateConfig():void{
			var _file:File = new File(File.applicationDirectory.resolvePath("AutoUpdateConfig.xml").nativePath);
			var stream:FileStream = new FileStream();
			stream.open(_file,FileMode.READ);
			var _data:String = stream.readUTFBytes(stream.bytesAvailable);
			stream.close();
			stream.open(_file,FileMode.WRITE);
			//= stream.readUTFBytes(stream.bytesAvailable);
			var xml:XML = 	<data> 
								<url_update></url_update>
								<url_update_folder></url_update_folder>
							</data>
			xml.version = this.serverVersion;
			xml.url_update = this.url_update;
			xml.url_update_folder = this.url_update_folder;
			
			var _configStr:String = '<?xml version="1.0" encoding="UTF-8"?>\n'+xml.toString();
			stream.writeUTFBytes(_configStr);
			stream.close();
		}*/
	}
}